/**
 * 
 */
package com.antilia.infomaresme.pages.testmaps;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.markup.html.IHeaderContributor;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
import org.apache.wicket.request.resource.ResourceReference;
import org.odlabs.wiquery.core.options.Options;

import wicket.contrib.gmap.GMap2;

import com.antilia.infomaresme.pages.testmaps.api.GControl;
import com.antilia.infomaresme.pages.testmaps.api.GLatLng;
import com.antilia.infomaresme.pages.testmaps.api.GMapType;
import com.antilia.infomaresme.pages.testmaps.api.GOverlay;

/**
 * @author Ernesto
 *
 */
public class GMap3 extends Panel implements IHeaderContributor {

	private static final long serialVersionUID = 1L;

	private static String url = "http://maps.googleapis.com/maps/api/js?sensor=";
	
	private static final ResourceReference JS = new JavaScriptResourceReference(GMap3.class, "wicket-gmap.js");
	
	private Options options = new Options();
	
	private WebMarkupContainer map;
	
	private int width = 500;
	
	private int height = 500;
	
	private final Set<GControl> controls = new HashSet<GControl>();

	private final List<GOverlay> overlays = new ArrayList<GOverlay>();
		
	/**
	 * @param id
	 */
	public GMap3(String id) {
		super(id);
		map = new WebMarkupContainer("map");
		map.setOutputMarkupId(true);
		setCenter(new GLatLng(41.4945971, 2.3646339, false));
		setZoom(8);
		setMapType(GMapType.ROADMAP);
		add(map);	
		map.add(new AttributeAppender("style", new AbstractReadOnlyModel<String>() {
		
			private static final long serialVersionUID = 1L;

			@Override
			public String getObject() {
				return "width:"+getWidth()+"px;"+"height:"+getHeight()+"px; position: relative;";
			}
		}));
	}
	
	public static void renderGMap(IHeaderResponse response, String mapKey, boolean sensor) {
		response.renderJavaScriptReference(url+sensor+"&key="+mapKey);
	}
	
	
	@Override
	public void renderHead(IHeaderResponse response) {
		//response.renderJavaScriptReference(url+sensor+"&key="+mapKey);
		response.renderJavaScriptReference(JS);
		String options = this.options.getJavaScriptOptions().toString();
		response.renderOnDomReadyJavaScript("new WicketMap3(\""+map.getMarkupId()+"\","+options+");");		
	}

	
	public GLatLng getCenter() {
		GLatLng center = (GLatLng)this.options.getComplexOption("center");
		return center;
	}

	public void setCenter(GLatLng center) {
		this.options.put("center", center);
	}

	public GMapType getMapType() {
		GMapType center = (GMapType)this.options.getComplexOption("mapTypeId");
		return center;
	}

	public void setMapType(GMapType mapType) {
		this.options.put("mapTypeId", mapType);
	}

	public int getZoom() {
		return this.options.getInt("zoom");
	}

	public void setZoom(int zoom) {
		this.options.put("zoom", zoom);
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}
	
	/**
	 * Add an overlay.
	 * 
	 * @param overlay
	 *            overlay to add
	 * @return This
	 */
	public GMap3 addOverlay(GOverlay overlay)
	{
		overlays.add(overlay);
		overlay.setParent(this);

		if (AjaxRequestTarget.get() != null && findPage() != null)
		{
			AjaxRequestTarget.get().appendJavaScript(overlay.getJSadd());
		}

		return this;
	}

	/**
	 * Remove an overlay.
	 * 
	 * @param overlay
	 *            overlay to remove
	 * @return This
	 */
	public GMap3 removeOverlay(GOverlay overlay)
	{
		while (overlays.contains(overlay))
		{
			overlays.remove(overlay);
		}

		if (AjaxRequestTarget.get() != null && findPage() != null)
		{
			AjaxRequestTarget.get().appendJavaScript(overlay.getJSremove());
		}

		overlay.setParent(null);

		return this;
	}

	/**
	 * Clear all overlays.
	 * 
	 * @return This
	 */
	public GMap3 removeAllOverlays()
	{
		for (GOverlay overlay : overlays)
		{
			overlay.setParent(null);
		}
		overlays.clear();
		if (AjaxRequestTarget.get() != null && findPage() != null)
		{
			AjaxRequestTarget.get().appendJavaScript(getJSinvoke("clearOverlays()"));
		}
		return this;
	}

	public List<GOverlay> getOverlays()
	{
		return Collections.unmodifiableList(overlays);
	}
	
	/**
	 * Convenience method for generating a JavaScript call on this GMap2 with the given invocation.
	 * 
	 * @param invocation
	 *            The JavaScript call to invoke on this GMap2.
	 * @return The generated JavaScript.
	 */
	// TODO Could this become default or protected?
	public String getJSinvoke(String invocation)
	{
		return "Wicket.maps['" + map.getMarkupId() + "']." + invocation + ";\n";
	}
	
	/**
	 * Add a control.
	 * 
	 * @param control
	 *            control to add
	 * @return This
	 */
	public GMap3 addControl(GControl control)
	{
		controls.add(control);

		if (AjaxRequestTarget.get() != null && findPage() != null)
		{
			AjaxRequestTarget.get().appendJavaScript(control.getJSadd(GMap3.this));
		}

		return this;
	}

	/**
	 * Remove a control.
	 * 
	 * @param control
	 *            control to remove
	 * @return This
	 */
	public GMap3 removeControl(GControl control)
	{
		controls.remove(control);

		if (AjaxRequestTarget.get() != null && findPage() != null)
		{
			AjaxRequestTarget.get().appendJavaScript(control.getJSremove(GMap3.this));
		}

		return this;
	}
}
